{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#导入numpy包后续进行数据处理\n",
    "import numpy as np # linear algebra\n",
    "\n",
    "#导入matplotlib包后续进行画图\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "#内嵌画图，使图像显示在该页面内\n",
    "%matplotlib inline\n",
    "\n",
    "#导入train_test_split包划分数据集为训练集，验证集\n",
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "#导入confusion_matrix(混淆矩阵)，查看真实值被正确或者错误预测的个数\n",
    "from sklearn.metrics import confusion_matrix"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\anaconda\\lib\\site-packages\\h5py\\__init__.py:34: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.\n",
      "  from ._conv import register_converters as _register_converters\n",
      "Using TensorFlow backend.\n",
      "C:\\anaconda\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:519: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint8 = np.dtype([(\"qint8\", np.int8, 1)])\n",
      "C:\\anaconda\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:520: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_quint8 = np.dtype([(\"quint8\", np.uint8, 1)])\n",
      "C:\\anaconda\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:521: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint16 = np.dtype([(\"qint16\", np.int16, 1)])\n",
      "C:\\anaconda\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:522: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_quint16 = np.dtype([(\"quint16\", np.uint16, 1)])\n",
      "C:\\anaconda\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:523: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint32 = np.dtype([(\"qint32\", np.int32, 1)])\n",
      "C:\\anaconda\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:528: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  np_resource = np.dtype([(\"resource\", np.ubyte, 1)])\n"
     ]
    }
   ],
   "source": [
    "#one-hot编码，采用独热码编码，直观来说就是有多少个状态就有多少比特，而且只有一个比特为1，其他全为0的一种码制，构造稀疏矩阵，解决分类值表示的问题对模型产生的负面影响\n",
    "from keras.utils.np_utils import to_categorical # convert to one-hot-encoding\n",
    "\n",
    "#导入顺序Sequential模型，后续可直接在Sequential上构建神经网络\n",
    "from keras.models import Sequential\n",
    "\n",
    "#Dense：全连接层；Dropout正则化数据；Flatten压平数据连接全连接层，Conv2D卷积层卷积计算，BatchNormalization数据规范化输出数据的均值接近0，其标准差接近1\n",
    "from keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPool2D, BatchNormalization\n",
    "\n",
    "#导入优化器Adam，基于一阶梯度的随机目标函数优化算法\n",
    "from keras.optimizers import Adam\n",
    "\n",
    "#导入ImageDataGenerator图像增广技术来扩充我们的数据集\n",
    "from keras.preprocessing.image import ImageDataGenerator\n",
    "\n",
    "#导入LearningRateScheduler动态修改学习率的回调函数\n",
    "from keras.callbacks import LearningRateScheduler"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#根据自己所下载数据设置对应的路径\n",
    "train_file = \"train.csv\"\n",
    "test_file = \"test.csv\"\n",
    "output_file = \"submission.csv\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#numpy导入数据，np.loadtxt\n",
    "#loadtxt(fname, dtype=<class 'float'>, comments='#', delimiter=None, converters=None, skiprows=0, usecols=None, unpack=False, ndmin=0)\n",
    "#fname要读取的文件、文件名、或生成器。\n",
    "#dtype数据类型，默认float。\n",
    "#comments注释。\n",
    "#delimiter分隔符，默认是空格。\n",
    "#skiprows跳过前几行读取，默认是0，必须是int整型。\n",
    "#usecols：要读取哪些列，0是第一列。例如，usecols = （1,4,5）将提取第2，第5和第6列。默认读取所有列。\n",
    "#unpack如果为True，将分列读取\n",
    "raw_data = np.loadtxt(train_file, skiprows=1, dtype='int', delimiter=',')\n",
    "\n",
    "\n",
    "\n",
    "#划分数据集为训练集和验证集\n",
    "#train_test_split(train_data,train_target,test_size=0.3, random_state=0)\n",
    "#train_data：被划分的样本特征集\n",
    "#train_target：被划分的样本标签\n",
    "#test_size：如果是浮点数，在0-1之间，表示测试集样本占比；如果是整数的话就是样本的数量\n",
    "#random_state：是随机数的种子,使每次产生的随机数一样\n",
    "x_train, x_val, y_train, y_val = train_test_split(raw_data[:,1:], raw_data[:,0], test_size=0.1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0.5,1,'28x28 data')"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1802b0a0588>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#subplots:子图显示，fig, ax = subplots(nrows, ncols，figsize）\n",
    "#fig代表整个图像，ax代表坐标轴和画的图\n",
    "#nrows，ncols：子图的行列数\n",
    "#figsize：显示图形大小\n",
    "fig, ax = plt.subplots(2, 1, figsize=(12,6))\n",
    "ax[0].plot(x_train[0])\n",
    "#设置标题\n",
    "ax[0].set_title('784x1 data')\n",
    "#图形显示x_train数据\n",
    "ax[1].imshow(x_train[0].reshape(28,28), cmap='gray')\n",
    "#设置标题\n",
    "ax[1].set_title('28x28 data')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Reshape image in 3 dimensions (height = 28px, width = 28px , canal = 1) （重塑三维图像）\n",
    "#784个输入，转成28 * 28 + 颜色通道\n",
    "#-1表示自动计算行数并填充\n",
    "#注意keras的颜色通道表示在最后一个参数(跟其他框架不同)\n",
    "x_train = x_train.reshape(-1, 28, 28, 1)\n",
    "x_val = x_val.reshape(-1, 28, 28, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#正则化数据，使矩阵内的数据规约到0到1之间，减少计算量，提升模型训练效率\n",
    "x_train = x_train.astype(\"float32\")/255.\n",
    "x_val = x_val.astype(\"float32\")/255."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]\n"
     ]
    }
   ],
   "source": [
    "#to_categorical(data,num_classes)：one-hot编码(独热码编码)，在对应的标签置1，其余的全部为0,num_classes表示多少个标签\n",
    "y_train = to_categorical(y_train)\n",
    "y_val = to_categorical(y_val)\n",
    "#例如：2  −>−>  [0,0,1,0,0,0,0,0,0,0]\n",
    "#example:\n",
    "print(y_train[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From C:\\anaconda\\lib\\site-packages\\keras\\backend\\tensorflow_backend.py:1259: calling reduce_prod (from tensorflow.python.ops.math_ops) with keep_dims is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "keep_dims is deprecated, use keepdims instead\n"
     ]
    }
   ],
   "source": [
    "#定义顺序模型Sequential，Sequential是多个网络层的线性堆叠\n",
    "#通常是由以下几层构成：数据输入层(Input)，卷积层(Convolutional)，池化层(Pooling)，全连接层(Dense)，数据输出层(Output)\n",
    "model = Sequential()\n",
    "\n",
    "#filters：整数，输出空间的维度（即卷积中滤波器的输出数量），滤波器做卷积计算用的，卷积计算的过程也正是图形匹配的过程。\n",
    "#kernel_size：一个整数，或者单个整数表示的元组或列表，指明1D卷积窗口的长度（即卷积滤波器窗口大小）。\n",
    "#activation：激活函数，relu激活函数是指让负数输出为0，正数原样输出。\n",
    "#传递一个input_shape的关键字参数给第一层，input_shape是一个tuple类型的数据，其中也可以填入None，如果填入None则表示此位置可能是任何正整数。数据的batch大小不应包含在其中\n",
    "#这里input_shape = (28, 28, 1)指28*28矩阵输入，1为颜色通道，灰色图则为1，rgb图则为3。\n",
    "model.add(Conv2D(filters = 16, kernel_size = (3, 3), activation='relu',\n",
    "                 input_shape = (28, 28, 1)))\n",
    "\n",
    "\n",
    "#BatchNormalization：规范化，该层在每个批次上将前一层的激活值重新规范化，即使得其输出数据的均值接近0，其标准差接近1\n",
    "#作用：（1）加速收敛（2）控制过拟合，可以少用或不用Dropout和正则（3）降低网络对初始化权重不敏感（4）允许使用较大的学习率\n",
    "model.add(BatchNormalization())\n",
    "\n",
    "model.add(Conv2D(filters = 16, kernel_size = (3, 3), activation='relu'))\n",
    "model.add(BatchNormalization())\n",
    "\n",
    "\n",
    "#MaxPooling图层只查看四个相邻像素并选取最大值。这将图像的大小减小了一半\n",
    "#strides设置查看窗口大小，即在相邻的几个像素中做处理\n",
    "model.add(MaxPool2D(strides=(2,2)))\n",
    "\n",
    "\n",
    "#Dropout：正则化层，随机地将每个训练样本的一部分权重替换为零，简单一点说在前向传播的时候，让某个神经元的激活值以一定的概率p停止。下面补充Dropout工作原理\n",
    "#作用：1.降低模型复杂度，增强模型的泛化能力，防止过拟合。2.降低了运算量。\n",
    "model.add(Dropout(0.25))\n",
    "\n",
    "\n",
    "model.add(Conv2D(filters = 32, kernel_size = (3, 3), activation='relu'))\n",
    "model.add(BatchNormalization())\n",
    "model.add(Conv2D(filters = 32, kernel_size = (3, 3), activation='relu'))\n",
    "model.add(BatchNormalization())\n",
    "\n",
    "model.add(MaxPool2D(strides=(2,2)))\n",
    "model.add(Dropout(0.25))\n",
    "\n",
    "#Flatten层用来将输入“压平”，即把多维的输入一维化，常用在从卷积层到(Convolution)全连接层(Dense)的过渡。\n",
    "#也就是说，Convolution卷积层之后是无法直接连接Dense全连接层的，需要把Convolution层的数据压平（Flatten）。\n",
    "model.add(Flatten())\n",
    "#Dense(512)表示output的shape为(*,32)\n",
    "model.add(Dense(512, activation='relu'))\n",
    "\n",
    "model.add(Dropout(0.25))\n",
    "model.add(Dense(1024, activation='relu'))\n",
    "model.add(Dropout(0.5))\n",
    "\n",
    "#Dense(10)表示output的shape为(*,10)，也就0-9的10个数字标签。\n",
    "model.add(Dense(10, activation='softmax'))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#图像增广技术扩充数据集\n",
    "#zoom_range参数可以调整图片在长或宽的方向进行放大，这个参数可以是一个数或者是一个list。当给出一个数时，图片同时在长宽两个方向进行同等程度的放缩操作；当给出一个list时，则代表[width_zoom_range, height_zoom_range]，即分别对长宽进行不同程度的放缩。而参数大于0小于1时，执行的是放大操作，当参数大于1时，执行的是缩小操作\n",
    "#width_shift_range是水平位置平移 。height_shift_range竖直位置平移。\n",
    "#其参数可以是[0, 1]的浮点数，也可以大于1，但最好不要大于1，超出原图范围的区域大多效果不好，其最大平移距离为图片长或宽的尺寸乘以参数，同样平移距离并不固定为最大平移距离，平移距离在 [0, 最大平移距离] 区间内。\n",
    "#rotation range的作用是用户指定旋转角度范围，其参数只需指定一个整数即可，可在 [0, 指定角度] 范围内进行随机角度旋转。\n",
    "datagen = ImageDataGenerator(zoom_range = 0.1,\n",
    "                            height_shift_range = 0.1,\n",
    "                            width_shift_range = 0.1,\n",
    "                            rotation_range = 10)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From C:\\anaconda\\lib\\site-packages\\keras\\backend\\tensorflow_backend.py:2880: calling reduce_sum (from tensorflow.python.ops.math_ops) with keep_dims is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "keep_dims is deprecated, use keepdims instead\n",
      "WARNING:tensorflow:From C:\\anaconda\\lib\\site-packages\\keras\\backend\\tensorflow_backend.py:1344: calling reduce_mean (from tensorflow.python.ops.math_ops) with keep_dims is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "keep_dims is deprecated, use keepdims instead\n"
     ]
    }
   ],
   "source": [
    "#API:model.compile(optimizer = '...', loss = '...', metrics = )\n",
    "#优化器optimizer：该参数可指定为已预定义的优化器名，如rmsprop、adagrad，或一个Optimizer类的对象\n",
    "#损失函数loss：该参数为模型试图最小化的目标函数，它可为预定义的损失函数名，如categorical_crossentropy、mse，也可以为一个损失函数。\n",
    "#指标列表metrics：对分类问题，我们一般将该列表设置为metrics=[‘accuracy’]。指标可以是一个预定义指标的名字,也可以是一个用户定制的函数.指标函数应该返回单个张量,或一个完成metric_name - > metric_value映射的字典.\n",
    "\n",
    "model.compile(loss='categorical_crossentropy', optimizer = Adam(lr=1e-4), metrics=[\"accuracy\"])\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#LearningRateScheduler动态修改学习率的回调函数，用于动态设置学习率，这里调用lambda函数\n",
    "annealer = LearningRateScheduler(lambda x: 1e-3 * 0.9 ** x)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/50\n",
      " - 209s - loss: 0.2878 - acc: 0.9142 - val_loss: 0.0943 - val_acc: 0.9700\n",
      "Epoch 2/50\n",
      " - 201s - loss: 0.1804 - acc: 0.9500 - val_loss: 0.0478 - val_acc: 0.9875\n",
      "Epoch 3/50\n",
      " - 199s - loss: 0.1525 - acc: 0.9571 - val_loss: 0.0406 - val_acc: 0.9900\n",
      "Epoch 4/50\n",
      " - 198s - loss: 0.1240 - acc: 0.9667 - val_loss: 0.0200 - val_acc: 0.9900\n",
      "Epoch 5/50\n",
      " - 197s - loss: 0.1159 - acc: 0.9676 - val_loss: 0.0500 - val_acc: 0.9875\n",
      "Epoch 6/50\n",
      " - 198s - loss: 0.1022 - acc: 0.9720 - val_loss: 0.0648 - val_acc: 0.9800\n",
      "Epoch 7/50\n",
      " - 199s - loss: 0.0888 - acc: 0.9759 - val_loss: 0.0373 - val_acc: 0.9875\n",
      "Epoch 8/50\n",
      " - 213s - loss: 0.0917 - acc: 0.9751 - val_loss: 0.0318 - val_acc: 0.9875\n",
      "Epoch 9/50\n",
      " - 179s - loss: 0.0759 - acc: 0.9797 - val_loss: 0.0394 - val_acc: 0.9900\n",
      "Epoch 10/50\n",
      " - 171s - loss: 0.0717 - acc: 0.9800 - val_loss: 0.0227 - val_acc: 0.9875\n",
      "Epoch 11/50\n",
      " - 171s - loss: 0.0654 - acc: 0.9816 - val_loss: 0.0292 - val_acc: 0.9925\n",
      "Epoch 12/50\n",
      " - 171s - loss: 0.0660 - acc: 0.9814 - val_loss: 0.0254 - val_acc: 0.9875\n",
      "Epoch 13/50\n",
      " - 191s - loss: 0.0591 - acc: 0.9842 - val_loss: 0.0387 - val_acc: 0.9925\n",
      "Epoch 14/50\n",
      " - 219s - loss: 0.0506 - acc: 0.9855 - val_loss: 0.0205 - val_acc: 0.9900\n",
      "Epoch 15/50\n",
      " - 192s - loss: 0.0514 - acc: 0.9852 - val_loss: 0.0135 - val_acc: 0.9950\n",
      "Epoch 16/50\n",
      " - 237s - loss: 0.0499 - acc: 0.9863 - val_loss: 0.0115 - val_acc: 0.9950\n",
      "Epoch 17/50\n",
      " - 224s - loss: 0.0513 - acc: 0.9858 - val_loss: 0.0153 - val_acc: 0.9925\n",
      "Epoch 18/50\n",
      " - 218s - loss: 0.0482 - acc: 0.9877 - val_loss: 0.0207 - val_acc: 0.9900\n",
      "Epoch 19/50\n",
      " - 201s - loss: 0.0490 - acc: 0.9857 - val_loss: 0.0266 - val_acc: 0.9925\n",
      "Epoch 20/50\n",
      " - 192s - loss: 0.0430 - acc: 0.9873 - val_loss: 0.0156 - val_acc: 0.9925\n",
      "Epoch 21/50\n",
      " - 186s - loss: 0.0394 - acc: 0.9882 - val_loss: 0.0203 - val_acc: 0.9900\n",
      "Epoch 22/50\n",
      " - 174s - loss: 0.0411 - acc: 0.9882 - val_loss: 0.0213 - val_acc: 0.9900\n",
      "Epoch 23/50\n",
      " - 159s - loss: 0.0402 - acc: 0.9890 - val_loss: 0.0285 - val_acc: 0.9900\n",
      "Epoch 24/50\n",
      " - 206s - loss: 0.0397 - acc: 0.9882 - val_loss: 0.0141 - val_acc: 0.9925\n",
      "Epoch 25/50\n",
      " - 218s - loss: 0.0402 - acc: 0.9884 - val_loss: 0.0151 - val_acc: 0.9925\n",
      "Epoch 26/50\n",
      " - 201s - loss: 0.0427 - acc: 0.9881 - val_loss: 0.0220 - val_acc: 0.9925\n",
      "Epoch 27/50\n",
      " - 195s - loss: 0.0383 - acc: 0.9894 - val_loss: 0.0156 - val_acc: 0.9925\n",
      "Epoch 28/50\n",
      " - 199s - loss: 0.0367 - acc: 0.9889 - val_loss: 0.0211 - val_acc: 0.9925\n",
      "Epoch 29/50\n",
      " - 221s - loss: 0.0336 - acc: 0.9898 - val_loss: 0.0201 - val_acc: 0.9900\n",
      "Epoch 30/50\n",
      " - 215s - loss: 0.0352 - acc: 0.9894 - val_loss: 0.0150 - val_acc: 0.9925\n",
      "Epoch 31/50\n",
      " - 249s - loss: 0.0371 - acc: 0.9888 - val_loss: 0.0174 - val_acc: 0.9925\n",
      "Epoch 32/50\n",
      " - 203s - loss: 0.0309 - acc: 0.9910 - val_loss: 0.0206 - val_acc: 0.9900\n",
      "Epoch 33/50\n",
      " - 272s - loss: 0.0360 - acc: 0.9897 - val_loss: 0.0128 - val_acc: 0.9900\n",
      "Epoch 34/50\n",
      " - 243s - loss: 0.0344 - acc: 0.9898 - val_loss: 0.0172 - val_acc: 0.9900\n",
      "Epoch 35/50\n",
      " - 205s - loss: 0.0319 - acc: 0.9903 - val_loss: 0.0151 - val_acc: 0.9925\n",
      "Epoch 36/50\n",
      " - 208s - loss: 0.0368 - acc: 0.9897 - val_loss: 0.0198 - val_acc: 0.9900\n",
      "Epoch 37/50\n",
      " - 202s - loss: 0.0335 - acc: 0.9898 - val_loss: 0.0156 - val_acc: 0.9925\n",
      "Epoch 38/50\n",
      " - 211s - loss: 0.0387 - acc: 0.9886 - val_loss: 0.0181 - val_acc: 0.9900\n",
      "Epoch 39/50\n",
      " - 193s - loss: 0.0317 - acc: 0.9900 - val_loss: 0.0178 - val_acc: 0.9900\n",
      "Epoch 40/50\n",
      " - 192s - loss: 0.0338 - acc: 0.9905 - val_loss: 0.0163 - val_acc: 0.9925\n",
      "Epoch 41/50\n",
      " - 188s - loss: 0.0355 - acc: 0.9895 - val_loss: 0.0205 - val_acc: 0.9925\n",
      "Epoch 42/50\n",
      " - 191s - loss: 0.0341 - acc: 0.9903 - val_loss: 0.0192 - val_acc: 0.9925\n",
      "Epoch 43/50\n",
      " - 190s - loss: 0.0309 - acc: 0.9912 - val_loss: 0.0185 - val_acc: 0.9900\n",
      "Epoch 44/50\n",
      " - 187s - loss: 0.0350 - acc: 0.9896 - val_loss: 0.0189 - val_acc: 0.9900\n",
      "Epoch 45/50\n",
      " - 186s - loss: 0.0326 - acc: 0.9905 - val_loss: 0.0218 - val_acc: 0.9900\n",
      "Epoch 46/50\n",
      " - 187s - loss: 0.0329 - acc: 0.9901 - val_loss: 0.0232 - val_acc: 0.9900\n",
      "Epoch 47/50\n",
      " - 186s - loss: 0.0359 - acc: 0.9895 - val_loss: 0.0217 - val_acc: 0.9900\n",
      "Epoch 48/50\n",
      " - 178s - loss: 0.0329 - acc: 0.9905 - val_loss: 0.0217 - val_acc: 0.9900\n",
      "Epoch 49/50\n",
      " - 176s - loss: 0.0322 - acc: 0.9906 - val_loss: 0.0219 - val_acc: 0.9900\n",
      "Epoch 50/50\n",
      " - 176s - loss: 0.0317 - acc: 0.9907 - val_loss: 0.0206 - val_acc: 0.9900\n"
     ]
    }
   ],
   "source": [
    "#fit_generator模型的训练\n",
    "#datagen.flow加载训练数据\n",
    "# batch_size=None, #每经过多少个sample更新一次权重，defult 32\n",
    "# epochs=1, #训练的轮数epochs\n",
    "# verbose=1, #0为不在标准输出流输出日志信息，1为输出进度条记录，2为每个epoch输出一行记录\n",
    "# validation_data=None, #验证集\n",
    "# steps_per_epoch=None, #将一个epoch分为多少个steps，也就是划分一个batch_size多大，比如steps_per_epoch=10，则就是将训练集分为10份，不能和batch_size共同使用\n",
    "# validation_steps=None, #当steps_per_epoch被启用的时候才有用，验证集的batch_size\n",
    "# callbacks=None,#list，list中的元素为keras.callbacks.Callback对象，在训练过程中会调用list中的回调函数\n",
    "\n",
    "hist = model.fit_generator(datagen.flow(x_train, y_train, batch_size=16),\n",
    "                           steps_per_epoch=500,\n",
    "                           epochs=50, #Increase this when not on Kaggle kernel\n",
    "                           verbose=2,  #1 for ETA, 0 for silent\n",
    "                           validation_data=(x_val[:400,:], y_val[:400,:]), #For speed\n",
    "                           callbacks=[annealer])\n",
    "#训练集的正确率和误差：acc，loss\n",
    "#验证集正确率和误差：val_acc，val_loss\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Final loss: 0.0166, final accuracy: 0.9952\n"
     ]
    }
   ],
   "source": [
    "#evaluate：模型评估，返回损失函数和指定的精确指标\n",
    "#evaluate(self, x, y, batch_size=32, verbose=1, sample_weight=None)\n",
    "#x_val：数据\n",
    "#y_val：标签\n",
    "#batch_size：整数，指定进行梯度下降时每个batch包含的样本数。训练时一个batch的样本会被计算一次梯度下降，使目标函数优化一步\n",
    "#verbose：日志显示，0为不在标准输出流输出日志信息，1为输出进度条记录，2为每个epoch输出一行记录\n",
    "#sample_weight：权值的numpy array，用于在训练时调整损失函数（仅用于训练）。可以传递一个1D的与样本等长的向量用于对样本进行1对1的加权，或者在面对时序数据时，传递一个的形式为（samples，sequence_length）的矩阵来为每个时间步上的样本赋不同的权\n",
    "final_loss, final_acc = model.evaluate(x_val, y_val, verbose=0)\n",
    "#修改输出格式\n",
    "print(\"Final loss: {0:.4f}, final accuracy: {1:.4f}\".format(final_loss, final_acc))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[411   0   0   0   1   0   0   0   0   0]\n",
      " [  0 455   0   0   0   0   1   1   0   0]\n",
      " [  0   0 408   0   0   0   0   1   0   0]\n",
      " [  0   0   0 441   0   0   0   0   1   0]\n",
      " [  0   0   0   0 400   0   0   0   0   0]\n",
      " [  0   0   0   0   0 391   0   0   2   0]\n",
      " [  1   0   0   0   2   0 411   0   0   0]\n",
      " [  1   0   1   0   0   0   0 447   0   0]\n",
      " [  0   0   0   0   0   0   0   0 374   1]\n",
      " [  0   0   0   0   3   0   0   1   3 442]]\n"
     ]
    }
   ],
   "source": [
    "#模型的预测：predict(x, batch_size=None, verbose=0, steps=None, callbacks=None)\n",
    "#x：输入数据，作为Numpy数组（如果模型有多个输入，则为Numpy数组列表）。\n",
    "#batch_size：整数，指定进行梯度下降时每个batch包含的样本数。训练时一个batch的样本会被计算一次梯度下降，使目标函数优化一步\n",
    "#verbose：日志显示，0为不在标准输出流输出日志信息，1为输出进度条记录，2为每个epoch输出一行记录\n",
    "#step：在宣布预测轮次结束之前的步骤总数（样本批次）\n",
    "# callbacks=None,#list，list中的元素为keras.callbacks.Callback对象，在训练过程中会调用list中的回调函数\n",
    "y_hat = model.predict(x_val)\n",
    "\n",
    "#numpy.argmax(a, axis=None, out=None)，返回沿轴axis最大值的索引。\n",
    "#a：数据\n",
    "#axis = 1表示沿横轴，axis = 0表示沿纵轴\n",
    "#返回取得最大值的索引\n",
    "y_pred = np.argmax(y_hat, axis=1)\n",
    "y_true = np.argmax(y_val, axis=1)\n",
    "\n",
    "#confusion_matrix(混淆矩阵)：查看真实值被正确或者错误预测的个数，对角线表示0到9被正确预测的个数\n",
    "cm = confusion_matrix(y_true, y_pred)\n",
    "print(cm)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#参考上述数据导入\n",
    "mnist_testset = np.loadtxt(test_file, skiprows=1, dtype='int', delimiter=',')\n",
    "x_test = mnist_testset.astype(\"float32\")\n",
    "x_test = x_test.reshape(-1, 28, 28, 1)/255.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#参考上述数据预测\n",
    "y_hat = model.predict(x_test, batch_size=64)\n",
    "y_pred = np.argmax(y_hat,axis=1)\n",
    "\n",
    "#将预测值写入文件保存\n",
    "with open(output_file, 'w') as f :\n",
    "    f.write('ImageId,Label\\n')\n",
    "    for i in range(len(y_pred)) :\n",
    "        f.write(\"\".join([str(i+1),',',str(y_pred[i]),'\\n']))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
